package org.csu.softwaremetrics_demo.metric.ck;

/**
 * NOC (Number of Children) 类
 * 用于计算一个类的直接子类数量
 * <p>
 * NOC是CK度量套件中的一个重要指标，用于评估类的责任范围：
 * 1. 高NOC值表示类被大量复用，可能是基础类或框架中的核心类
 * 2. 高NOC值也可能表示类的设计不当，可能存在不恰当的继承层次
 * 3. NOC值有助于评估对系统的潜在影响，高NOC值的类修改需谨慎
 */


import org.csu.softwaremetrics_demo.entity.common.CKMetricSingleClass;
import org.csu.softwaremetrics_demo.entity.result.Result;
import org.csu.softwaremetrics_demo.entity.result.impl.CKMetricResult;
import org.csu.softwaremetrics_demo.metric.Metric;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.TypeDeclaration;

public class NOC extends ASTVisitor implements Metric<CKMetricSingleClass> {

    /**
     * 存储所有类的度量结果报告
     */
    private CKMetricResult result;

    /**
     * 用于处理可能不在当前编译单元中的父类的子类计数
     */
    private final NOCExtras extras;

    /**
     * 构造函数，初始化NOC对象
     *
     * @param extras 用于处理不在当前编译单元中的父类的子类计数
     */
    public NOC(NOCExtras extras) {
        this.extras = extras;
    }

    /**
     * 访问类型声明节点，计算其父类的NOC值
     * 如果父类在当前报告中，直接增加其NOC计数
     * 否则，将其添加到extras中以便后续处理
     *
     * @param node 类型声明节点
     * @return 是否继续访问子节点
     */
    @Override
    public boolean visit(TypeDeclaration node) {
        // 获取当前类型声明节点的类型绑定
        ITypeBinding binding = node.resolveBinding();
        // 获取当前类型的父类类型绑定
        ITypeBinding father = binding.getSuperclass();
        // 如果父类不为空
        if (father != null) {
            // 从结果报告中获取父类的度量结果
            CKMetricSingleClass fatherCk = result.getByClassName(father.getBinaryName());
            // 如果父类在当前报告中，增加其NOC计数
            if (fatherCk != null) fatherCk.incNoc();
            // 否则，将父类添加到extras中以便后续处理
            else extras.plusOne(father.getBinaryName());
        }

        // 返回false，表示不继续访问子节点
        return false;
    }

    /**
     * 执行度量计算
     *
     * @param cu           编译单元
     * @param singleMetric 单个类的度量结果
     * @param result       度量结果报告
     */
    @Override
    public void execute(CompilationUnit cu, CKMetricSingleClass singleMetric, Result result) {
        // 将结果报告赋值给当前对象的result字段
        this.result = (CKMetricResult) result;
        // 接受编译单元的访问
        cu.accept(this);
    }

    /**
     * 设置单个类的度量结果
     *
     * @param singleMetric 单个类的度量结果
     */
    @Override
    public void setSingleMetric(CKMetricSingleClass singleMetric) {
        // 当前实现为空，不进行任何操作
    }
}
